// 事件循环(EventLoop)伪代码

while (macroQueue.waitForMessage()) {
  // 1. 执行完调用栈上 当前的宏任务
  // call stack

  // 2. 遍历微任务队列，把微任务队列里面所有的任务都执行完成（清空微任务队列）
  // 微任务中又可以向微任务中添加微任务 (不建议这样做，容易死循环)
  for (let i = 0; i < microQueue.length; i++) {
    // 获取并执行下一个微任务(先进先出)
    microQueue[i].processNextMessage();
  }

  // 渲染线程

  // 从宏任务队列中取出来一个任务，进入下一个任务循环
  macroQueue.processNextMessage();
}

/**
 * 产生宏任务的方法
 * script 标签
 * setTimeOut
 * setInterval
 * setImmediate （IE/node API）
 * 注册事件
 */

/**
 * 产生微任务的方法
 * Promise
 * MutationObserver
 * queueMicrotask
 */

/**
 * 微任务的优势
 * 减少操作中用户可感知到的延迟(微任务执行完成之后再去渲染)
 * 确保任务的一致性
 * 批量操作的优化
 */